/**
 * 
 */
package com.xbang.attendance.security.interceptor;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.ConfigAttributeEditor;
import org.springframework.security.intercept.web.FilterInvocation;
import org.springframework.security.intercept.web.FilterInvocationDefinitionSource;
import org.springframework.security.util.AntUrlPathMatcher;
import org.springframework.security.util.RegexUrlPathMatcher;
import org.springframework.security.util.UrlMatcher;

import com.xbang.attendance.entity.system.Menu;

/**
 * @author dev.zhang
 */
public class SecureResourceFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource, InitializingBean {

	private UrlMatcher urlMatcher;

	private boolean useAntPath = true;

	private boolean lowercaseComparisons = true;

	/**
	 * @param useAntPath
	 *            the useAntPath to set
	 */
	public void setUseAntPath(boolean useAntPath) {
		this.useAntPath = useAntPath;
	}

	/**
	 * @param lowercaseComparisons
	 */
	public void setLowercaseComparisons(boolean lowercaseComparisons) {
		this.lowercaseComparisons = lowercaseComparisons;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {

		// default url matcher will be RegexUrlPathMatcher
		this.urlMatcher = new RegexUrlPathMatcher();

		if (useAntPath) { // change the implementation if required
			this.urlMatcher = new AntUrlPathMatcher();
		}

		// Only change from the defaults if the attribute has been set
		if ("true".equals(lowercaseComparisons)) {
			if (!this.useAntPath) {
				((RegexUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(true);
			}
		} else if ("false".equals(lowercaseComparisons)) {
			if (this.useAntPath) {
				((AntUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(false);
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.intercept.ObjectDefinitionSource#getAttributes(java.lang.Object)
	 */
	public ConfigAttributeDefinition getAttributes(Object filter) throws IllegalArgumentException {

		FilterInvocation filterInvocation = (FilterInvocation) filter;
		String requestURI = filterInvocation.getRequestUrl();

		setViewToolCurrSubMenu(filterInvocation, requestURI);
		Map<String, String> urlAuthorities = this.getUrlAuthorities(filterInvocation);
		setSubMenuStyleAttribute(filterInvocation, requestURI);
		String grantedAuthorities = null;
		for (Iterator<Map.Entry<String, String>> iter = urlAuthorities.entrySet().iterator(); iter.hasNext();) {
			Map.Entry<String, String> entry = iter.next();
			String url = entry.getKey();

			if (urlMatcher.pathMatchesUrl(url, requestURI)) {
				grantedAuthorities = entry.getValue();
				break;
			}

		}

		if (grantedAuthorities != null) {
			ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
			configAttrEditor.setAsText(grantedAuthorities);
			return (ConfigAttributeDefinition) configAttrEditor.getValue();
		}

		return null;
	}

	private void setViewToolCurrSubMenu(FilterInvocation filterInvocation, String requestURI) {
		if (filterInvocation.getHttpRequest().getSession().getAttribute("currentSubmenus") != null) {
			List<Menu> roleSubmenus = (List<Menu>) filterInvocation.getHttpRequest().getSession().getAttribute("currentSubmenus");
			String[] urls;
			if (requestURI.indexOf("/") != -1) {
				urls = requestURI.split("/");
				boolean isViewRequest = false;
				if (requestURI.endsWith(".jsp")) {
					isViewRequest = true;
				}

				for (Menu menu : roleSubmenus) {
					String[] menuUrls = menu.getUrl().split("/");
					if (menuUrls.length > 1) {
						if (menuUrls[0].equals(urls[isViewRequest ? urls.length - 3 : urls.length - 2])
								&& menuUrls[1].equals(urls[isViewRequest ? urls.length - 2 : urls.length - 1])) {
							filterInvocation.getHttpRequest().setAttribute("currViewBarSubMenu_", menu);
							break;
						}
					}
				}
			}
		}
	}

	/**
	 * 设置子菜单的样式
	 * 
	 * @param filterInvocation
	 *            request 提取上下文
	 * @param requestURI
	 *            reques url
	 * @author dev.zhang
	 */
	private void setSubMenuStyleAttribute(FilterInvocation filterInvocation, String requestURI) {
		String startPosFix = "";
		if (requestURI.endsWith(".jsp")) {
			filterInvocation.getHttpRequest().setAttribute("currSubMenu_", requestURI.split("/")[requestURI.split("/").length - 2]);
			startPosFix = requestURI.split("/")[requestURI.split("/").length - 3];
		} else if (requestURI.indexOf("/") != -1) {
			filterInvocation.getHttpRequest().setAttribute("currSubMenu_", requestURI.split("/")[requestURI.split("/").length - 1]);
			startPosFix = requestURI.split("/")[requestURI.split("/").length - 2];
		} else {
			filterInvocation.getHttpRequest().removeAttribute("currSubMenu_");
		}
		String subMenuChar = filterInvocation.getHttpRequest().getAttribute("currSubMenu_") != null ? filterInvocation.getHttpRequest().getAttribute(
				"currSubMenu_").toString() : null;
		if (subMenuChar != null && (subMenuChar.equals("detail") || subMenuChar.equals("report"))) {
			filterInvocation.getHttpRequest().setAttribute("currSubMenu_", startPosFix.concat("-").concat(subMenuChar));
		}
		if (subMenuChar != null && subMenuChar.equals("sales") && startPosFix.equals("report")) {
			filterInvocation.getHttpRequest().setAttribute("currSubMenu_", subMenuChar.concat("-").concat(startPosFix));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.intercept.ObjectDefinitionSource#getConfigAttributeDefinitions()
	 */
	@SuppressWarnings("unchecked")
	public Collection getConfigAttributeDefinitions() {
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.intercept.ObjectDefinitionSource#supports(java.lang.Class)
	 */
	@SuppressWarnings("unchecked")
	public boolean supports(Class clazz) {
		return true;
	}

	/**
	 * 
	 * @param filterInvocation
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Map<String, String> getUrlAuthorities(FilterInvocation filterInvocation) {
		ServletContext servletContext = filterInvocation.getHttpRequest().getSession().getServletContext();
		return (Map<String, String>) servletContext.getAttribute("urlAuthorities");
	}

}
